Property created with #property performs differently - python-3.x

>>> class test():
name = 'tiger'
def __init__(self,value):
self.name = value
>>> class subtest(test): pass
>>> a = subtest('cat')
>>> super(subtest,subtest).name
'tiger'
When I use super(class, class) to access a normal property of class, it gets value of that property. However, when I rewrite that property with #property, it turns out to a property object, why and what happend?
>>> class test():
name = 'tiger'
def __init__(self,value):
self._name = value
#property
def name(self):
return self._name
#name.setter
def name(self,value):
self._name = value
>>> class subtest(test): pass
>>> super(subtest,subtest).name
<property object at 0x03AB6300>

Related

Error trying to access a parent variable from his child class

So I have this class:
class UniversalHash(HashClass):
##################################################
def __init__(self):
super().__init__()
self.__MParamK = int(0)
self.__MParamC = int(0)
self.__MParamD = int(0)
# Override #
def FindHash(self, Key):
return (((self.__MParamK * Key) + self.__MParamC) % self.__MParamD) % self.__MParamL
def SetParamK(self, Value):
self.__MParamK = Value
def SetParamC(self, Value):
self.__MParamC = Value
def SetParamD(self, Value):
self.__MParamD = Value
And the parent class:
class HashClass:
##################################################
def __init__(self):
self.__MParamL = int(0)
def SetParamL(self, Value):
self.__MParamL = Value
def GetParamL(self):
return self.__MParamL
def FindHash(self, Key):
pass
When I try to access to the variable __MParamL (the variable created in the parent), it gives me an exception telling me that the variable is not an attribute of this class, I have searched on the web and it seems this is the correct way to write the code (maybe the overridden function is the problem?). Any help is appreciated
When you name an instance attribute with a leading double underscore, it will get name mangled, E.g.,
>>> class A:
... def __init__(self):
... self.x = 42
... self.__y = 42
...
>>> a = A()
>>> vars(a)
{'x': 42, '_A__y': 42}
Instead, you should just use a single underscore, E.g.,
>>> class A:
... def __init__(self):
... self.x = 42
... self._y = 42
...
>>> a = A()
>>> vars(a)
{'x': 42, '_y': 42}

#property - method calling logic

Here is the code:
class Duck():
def __init__(self,input_name):
self.__name = input_name
#property
def name(self):
print('inside the getter')
return self.__name
#name.setter
def name(self):
print('inside the setter')
self.__name = input_name
fowl = Duck("Howard")
So, "dot" is the connection between object and method. That's to say, type fowl.name will get "Howard", because the object called name and returned self.__name.
My question is if I type fowl.name = "cat", why I won't get anything from #property, getter. And how the program knew it's a setter? Because I used "="?

Program to use class method in python

class student:
college = "tcet"
def __init__(self,name,age,marks):
self.name = name
self.age = age
self.marks = 90
#staticmethod #This is a StaticMethod Decorator
def info():
return "This is data of students"
#classmethod #This is a ClassMethod Decorator
def college(cls):
return cls.college
s1 = student("shubham",19,100)
s2 = student("luffy",20,99.99)
print(student.college())
print(student.info())
Getting this error:
<bound method student.college of <class '__main__.student'>>
Methods are just another form of attributes in Python, so by naming a method college when a class attribute college has already been defined, the method object will replace the class attribute college that was holding the string "tcet".
You can correct this by simply naming the attribute differently:
class student:
_college = "tcet"
#classmethod
def college(cls):
return cls._college

Python: for multiple properties use one getter and setter method

I have created a class that has multiple properties. I want to use one function for the getter method and the second one for the setter method.
class person:
def __init__(self, fname, lname, city, state):
# make all attributes as private
self._fname = fname
self._lname = lname
self._city = city
self._state = state
#property # get method
def fname(self):
return self._fname
#fname.setter # set method
def fname(self,fname):
self._fname = fname
#property
def lname(self):
return self._lname
#lname.setter
def lname(self,lname):
self._lname = lname
#property
def city(self):
return self._city
#city.setter
def city(self, city):
self._city = city
#property
def state(self):
return self._state
#state.setter
def state(self, state):
self._state = state
How to use all properties for one get methods and one set method?
e.g.:
def get(self):
return self._attr
def set(self,value):
self._attr = value
class person:
def __set_name__(self, name):
self.name = name
def __get__(self, obj, type=None) -> object:
return obj.__dict__.get(self.name)
def __set__(self, obj, value) -> None:
obj.__dict__[self.name] = value
my_value = person
my_values.fname = 'Shivam'
my_values.lname = 'Gupta'
print(my_values.fname) #--> Shivam
print(my_values.lname) #--> Gupta

Python overriding default attribute assignment

for a specific framework i work with, i need to define object attributes as special classes, for example, instead of writing this:
class A:
def __init__(self):
self.some_int = 2
i would need to write:
class A:
def __init__(self):
self.some_int = SpecialIntWrapper(name = "some_int", value = 2)
I would like to somehow override operators/methods so that typing the first code (self.some_int = 2) will call SpecialIntWrapper behind the scenes, with the attribute name and value.
is this possible?
Basically there are two ways - via a #property decorator (preferable unless you want to affect arbitrary names)
class MyClass:
def __init__(self):
self.some_int = 2
# if you know the name of the property define it as a property - a getter
#property
def some_int(self):
return self._some_int
# and a setter
#some_int.setter
def some_int(self, value):
self._some_int = SpecialIntWrapper("some_int", value)
or overloading the __setattr__ magic method
class MyClass:
def __init__(self):
self.some_int = 2
def __setattr__(self, name, value):
# in general if you dont know the names of the properties
# beforehand you can somehow filter them here
if name == "some_int":
super().__setattr__(name, SpecialIntWrapper(name=name, value=value))
else:
# to use the setattr in a default way, just call it via super(Python 3)
super().__setattr__(name, value)
either way the some_int will be initialized to the SpecialIntWrapper instance
>>>print(MyClass().some_int)
<__main__.SpecialIntWrapper object at 0x03721810>
Something like this
class SpecialIntWrapper:
def __init__(self, name, value):
pass
class MyClass:
def __init__(self):
self.some_int = 3
def __setattr__(self, key, value):
if key == 'some_int':
self.__dict__[key] = SpecialIntWrapper(key, value)
else:
self.__dict__[key] = value
print(MyClass().some_int)
# >>> <__main__.SpecialIntWrapper object at 0x1076f1748>

Resources