2

如何在其类/子类之外限制属性的创建?

__all__ = ["Employee","Salary","Wage"]
##################################################################################################
class Person(object):
    def __init__(self,fname,lname,gender):
        self.__setfname(fname) # "We are all adults." vs. "Name mangling."
        self.__setlname(lname)
        self.__setgender(gender)
    def __setfname(self,fname): self.__fname = fname
    def __setlname(self,lname): self.__lname = lname
    def __setgender(self,gender): self.__gender = gender
    def getname(self): return "{} {}".format(self.__fname,self.__lname)
    def getformattedname(self):
        if(self.__gender.lower() == "m"):
            return "Mr. {}".format(self.getname())
        if(self.__gender.lower() == "f"):
            return "Ms. {}".format(self.getname())
        if(self.__gender.lower() == ""):
            return "{}".format(self.getname())
class Payment(object):
    def __init__(self,amount,currency="INR"): # currency="USD"
        self.__setamount(amount)
        self.__setcurrency(currency)
    def __setamount(self,amount): self.__amount = amount
    def __setcurrency(self,currency): self.__currency = currency
    def getamount(self): return "{}".format(self.__amount)
    def getformattedamount(self): return "{} {}".format(self.getamount(),self.__currency)
##################################################################################################
##################################################################################################
class Employee(Person):
    def __init__(self,fname,lname,gender): super(Employee,self).__init__(fname,lname,gender)
    def __str__(self): return self.getformattedname()
class Salary(Payment):
    def __init__(self,amount,currency="INR"): super(Salary,self).__init__(amount,currency)
    def __str__(self): return self.getformattedamount()
class Wage(Payment):
    def __init__(self,amount,currency="INR"): super(Wage,self).__init__(amount,currency)
    def __str__(self): return self.getformattedamount()
##################################################################################################

我对此没意见:

e1._Person__fname = "Spam"
s1._Payment__amount = "1000000000000000"

但以下代码创建了新属性:

e1.fname = "New"
s1.amount = -10

import re
from com.example.model import Employee,Salary,Wage

def printzip(l1,l2): print(list(zip([str(e) for e in l1],[str(e) for e in l2])))

(e1,e2) = (Employee("Sandeep","Mehta","m"),Employee("Varsha","Mehta","f"))
(s1,s2) = (Salary(3000,"USD"),Salary(3000,"USD"))

printzip([e1,e2],[s1,s2])
e1.fname = "New"
s1.amount = -3000
e1._Person__fname = "Spam"
s1._Payment__amount = "3000000000000000"

for e in enumerate([e for e in dir(e1) if not (re.search(r"^__.*__$",e))]): print(e)
for e in enumerate([e for e in dir(s1) if not (re.search(r"^__.*__$",e))]): print(e)
printzip([e1],[s1])

Python空闲

4

4 回答 4

6

不要尝试这样做。别人对你的班级做什么不是你的事。您应该记录预期可用的属性,如果有人想滥用它,那是他们的问题,而不是您的问题。

“我们在这里都是同意的成年人”是 Pythonic 哲学。

于 2013-09-02T17:04:49.010 回答
4

我们可以滥用__slots__,尽管 的主要目的__slots__不是避免创建额外的属性:

class Person(object):
    __slots__ = ('_Person__fname', '_Person__lname', '_Person__gender')
    ...

class Employee(Person):
    __slots__ = () # All subclasses also need define __slots__ 
    ...

e1._Person__fname = "Spam"  # Fine
e1.fname = "New"            # AttributeError: 'Employee' object has no attribute 'fname'

请注意,使用__slots__,不会创建实例__dict__,这可能会破坏使用它们的某些代码。

于 2013-09-02T17:01:47.630 回答
3

您在寻找房产吗?

class Foo(object):
    def __init__(self):
        self._amount = 0

    @property
    def amount(self):
        return self._amount


f = Foo()
print f.amount  # ok
f.amount = 100  # error
于 2013-09-02T17:04:33.543 回答
3

你可以这样做:

class A:
    def __setattr__(self, attr, val):
        try :
            class_name, varname = attr.split('__', 1)
            if class_name == '_' + self.__class__.__name__:
                self.__dict__[attr] = val
            else:
                raise AttributeError
        except ValueError:
            raise AttributeError

演示:

>>> %run so.py
>>> a = A()
>>> a._A__foo = 1
>>> a._A__bar = 2
>>> a._A = 2
Traceback (most recent call last):
  File "<ipython-input-28-eace128dbfc5>", line 1, in <module>
    a._A = 2
  File "/home/monty/py/so.py", line 10, in __setattr__
    raise AttributeError
AttributeError

>>> a.A__bar = 2
Traceback (most recent call last):
  File "<ipython-input-29-57210782cd6a>", line 1, in <module>
    a.A__bar = 2
  File "/home/monty/py/so.py", line 8, in __setattr__
    raise AttributeError
AttributeError

>>> a._A__spam = 3
>>> a.__dict__
{'_A__foo': 1, '_A__spam': 3, '_A__bar': 2}
于 2013-09-02T17:01:14.157 回答