Gå til innhold

[Løst] Python: Hjelp til å få til counter i en klasse


Anbefalte innlegg

Heisann

 

Jeg er relativt ny i Python, og lurte på om noen kunne hjelpe meg med å få til en teller. Jeg ønsker at hver gang jeg kommer inn i "else" skal "counter" øke med 1 (starte på 0). Verdien av counter skal deretter printes ut (print "programmet har gått inn i else " + counter + " ganger."

Jeg har kommet frem til at jeg må angi at counter=0 rett ovenfor for-løkka nederst, hvis ikke blir den nullstilt hver gang for-løkka går. Men jeg sliter med å få returnert den nye verdien av counter fra write-klassen...

 

Jeg har følgende utsnitt av en kode:

 

class write:
   def impWrite(self,prog):

       self.prog = prog

.
.
.

       if findPatTitle[0] == version2:
           print name2 + updated


       else:

           print outdated1 + name2 + outdated2 + version2 + outdated3 + findPatTitle[0]

.
.
.

for i in range(1, linjer+1):
   Nr = str(i)
   programNewline = getIndex.readline()
   program = programNewline.rstrip('\n')
   prog = program
   programObject=write()
   programObject.impWrite(prog)

Lenke til kommentar
Videoannonse
Annonse
  • 1 måned senere...

Humm.. Et par merkelige ting der... Først og fremst, hvorfor lager du en ny class instance i hver loop? Og hva med "prog = program" ? Og, fra det eksemplet du viser, ser jeg ikke noen grunn til at impWrite er inne i en class definisjon, istedet for en vanlig funksjon.

 

Uansett, er fire måter å gjøre det du spør om, som jeg kommer på i farten.

 

1. Bruke en global variabel

2. Bruke en class variabel (og ikke lage ny class instance hele tiden)

3. Bruke en static class variabel (litt hårete)

4. få impWrite til å returnere en verdi som indikerer om else var kjørt, og holde orden på det i for-løkken

Lenke til kommentar


class Foo:
 def __init__(self):
   self.else_count = 0
   self.do_else = False
 def bar(self):
   if not self.do_else:
     print "if..."
   else:
     self.else_count += 1
     print "else %s ganger" % self.else_count
   self.do_else = not self.do_else

foo = Foo()
for i in range(1, 10):
 foo.bar()

 

Output:

if...
else 1 ganger
if...
else 2 ganger
if...
else 3 ganger
if...
else 4 ganger
if...

Endret av torbjørn marø
Lenke til kommentar

Takker for svar =)

 

Glemte å si at jeg fikk det til ved å la det som sto inni write-klassen skje rett i for-løkka.

 

Gjorde det sånn i mitt nybegynnende forsøk på å holde ting ryddig og adskilt, men fant ut at det var best å la det være =)

Lenke til kommentar

Enkel og fin løsning torbjørn.

En mere universell vil være og skrive en counter class.

Da kan man bare sette in counter() i den blokken man ønsker telling.

 

Tar litt om dette.

class Counter(object):
   def __init__(self, fvalue=0, inc=lambda x: x + 1):
       self.inc = inc
       self.val = fvalue

   def __call__(self):
       old = self.val
       self.val = self.inc(self.val)
       return old

class foo(object):
   def bar(self, num, counter):
       if num < 5:
           return 'Less than 5'
       else:
           return 'More than 5 count %s' % counter()

Tester ut i IDLE.

>>> counter = Counter(1)
>>> f = foo()
>>> for i in range(10):
...     f.bar(i, counter)
...     
'Less than 5'
'Less than 5'
'Less than 5'
'Less than 5'
'Less than 5'
'More than 5 count 1'
'More than 5 count 2'
'More than 5 count 3'
'More than 5 count 4'
'More than 5 count 5'
>>> 

Vi ser Counter class fungerer fint i else blokken.

Kan lagre kun Counter class(counter.py i pythonpath) og importere den når vi trenger telling.

from counter import Counter

class foo():
   def bar(self, num, counter):
       if num < 5:
           return 'Less than 5'
       else:
           return 'More than 5 count %s' % counter()

Teste ut,og denne gangen teste og telle ned.

>>> counter = Counter(-5)
>>> f = foo()
>>> for i in range(10):
...     f.bar(i, counter)
...     
Less than 5
Less than 5
Less than 5
Less than 5
Less than 5
More than 5 count -5
More than 5 count -4
More than 5 count -3
More than 5 count -2
More than 5 count -1
>>> 

Endret av SNIPPSAT
  • Liker 1
Lenke til kommentar

hehe, er mye gøy man kan gjøre med de der :)

 

>>> class moo(dict):
def __getattr__(self, name):
	return self.__dict__.get(name, None)
def __setattr__(self, name, value):
	self.__dict__[name] = value
def __delattr__(self, name):
	del self.__dict__[name]


>>> m = moo()
>>> m.asd
>>> m.asd = "ossom"
>>> m.asd
'ossom'
>>> del m.asd
>>> m.asd
>>> 

 

Et annet triks:

 

>>> class lurings(object):
bla = [0]
def __call__(self):
	self.bla[0] = self.bla[0] + 1
def getval(self):
	print self.bla[0]


>>> for x in range(20):
lurings()()


>>> lurings().getval()
20
>>> 

 

Edit: Ble litt gira her, så et par andre triks:

 

>>> ' '.join([str(x) for x in range(41) if x%2==0])
'0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40'

>>> def evens(x):
i = 0
while i <= x:
	yield i
	i = i + 2


>>> for x in evens(40): print x,

0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
>>> for x in evens(40): print x%3 == 0 and x or x > 9 and "__" or "_",

_ _ _ 6 _ __ 12 __ __ 18 __ __ 24 __ __ 30 __ __ 36 __ __
>>>

Endret av Terrasque
Lenke til kommentar

Python har flere funksjoner som en klasse kan kalle på seg selv.

Kan bryte det ned litt.

>>> c = Counter() #__init__ get run now,acts as an constructor
>>> dir(c)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'inc', 'val']

>>> c() #Now when we do a call with() __call__ will run
0
>>> c()
1
>>> c.__call__()
2
>>> c()
3
>>> 

Viss vi skriver om __call__ og bruker et vanlig navn.

class Counter(object):
   def __init__(self, fvalue=0, inc=lambda x: x + 1):
       self.inc = inc
       self.val = fvalue

   def call_me(self):
       old = self.val
       self.val = self.inc(self.val)
       return old

 

>>> c = Counter() #__init__ get run,acts as an constructor
>>> c()
Traceback (most recent call last):
 File "<interactive input>", line 1, in <module>
TypeError: 'Counter' object is not callable

>>> #Python do not find any __call__ method
#Have to call it with name
>>> c.call_me()
0
>>> c.call_me()
1
>>> c.call_me()
2
>>> 

Tar med en til med __call__ her også med "special method" __str__

Alle __something__ er "special method" i python.

class Animal(object):
   def __init__(self):
       self.stomach = []

   def __call__(self,food):
       self.stomach.append(food)

   def __str__(self):
       '''return a human-readable string'''
       return 'In stomach %s' % (self.stomach)

 

>>> dog = Animal() #__init__
>>> dog('beef') #__call__ now with one argument
>>> print dog   #__str__
In stomach ['beef']

>>> dog('Cat') 
>>> print dog  
In stomach ['beef', 'Cat']
>>> 

Lenke til kommentar
Edit: Ble litt gira her, så et par andre triks:

Ja kan forsette litt ettsom det er litt stille i python delen.

List comprehensions er en vanlig måte og skrive på i python og går ikke under triks kategorien lengere.

' '.join([str(x) for x in range(41) if x%2==0])

Viss vi skriver den om til en mer vanlig loop.

>>> l = []
>>> for i in range(41):
...     if i%2 == 0:
...         l.append(str(i))
...         
>>> ' '.join(l)
'0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40'
>>> 

Viss vi tar bort og konvertere til string.

>>> [x for x in range(41) if x%2==0]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40]

Så litt power med og bytte til generator expression,kun bytte [] til ()

>>> g = (x for x in range(41) if x%2==0)
>>> g
<generator object <genexpr> at 0x032AA968>
>>> g.next()
0
>>> g.next()
2
>>> 

Hva er fordelen med dette?

Med generator lese kun data som trenges inn til minnet.

g.next() lese inn til minnet tømmes også videre.

>>> g = (x for x in range(41) if x%2==0)
>>> for i in g:
...     print i,
...     
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40

 

Vi kan sende generator object inn i andre funksjoner.

Si at vi vil legg til 5 på alle even tallene i generator objectet.

def plusfive(gen):
   for n in gen:
       yield n + 5

g = (x for x in range(41) if x%2==0)

for n in plusfive(g):
   print n,
#5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45

Dette var litt python power :cool:

Lenke til kommentar

Er ganske mange triks på http://stackoverflow.com/questions/101268/hidden-features-of-python :)

 

Et trick som ble nevnt der, som jeg av og til bruker; decorators

 

(eksempel kopiert fra siden)

 

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

 

Ikke ofte jeg bruker, men utrolig nyttig i noen tilfeller :D

 

Edit: Et annet triks jeg vil highlighte:

 

def draw_point(x, y):
   # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

 

Også utrolig nyttig i noen tilfeller

Endret av Terrasque
  • Liker 1
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...